package Advanced;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class demo16字符流和Properties集合 {

	public static void main(String[] args) throws IOException {
//		reader();
//		writer();
//		renew();
//		tryCatch();
//		properties();
//		propertiesStore();
		propertiesLoad();
	}
	public static void reader() throws IOException {
		/* 使用字节流读取中文文件
		 * 一个中文：
		 * 		GBK：占用两个字节
		 * 		UTF-8：占用三个字节
		 * 
		 * java.io.Reader：字符输入流，是字符输入流最顶层的父类，定义了一些共性的成员方法，是一个抽象类
		 * 共性的成员方法：
		 * 		int read() 读取单个字符并返回
		 * 		int read(char[] cbuf) 一次读取多个字符，将字符读入数组
		 * 		void close() 关闭该流并释放与之相关联的所有资源
		 * 
		 * java.io.FileReader extends InputStreamReader extends Reader
		 * FileReader：文件字符输入流
		 * 作用：把硬盘文件中的数据以字符的方式读取到内存中
		 * 
		 * 构造方法：
		 * 		FileReader(String filename)
		 * 		FileReader(File file)
		 * 		参数：读取文件的数据源
		 * 			String filename：文件的路径
		 * 			File file：一个文件
		 * 		FileReader构造方法的作用：
		 * 			1、创建一个FileReader对象
		 * 			2、会把FileReader对象指向要读取的文件
		 * 字符输入流的使用步骤：
		 * 		1、创建FileReader对象，构造方法中绑定要读取的数据源
		 * 		2、使用FileReader对象中的方法read读取文件
		 * 		3、释放资源		
		 * */
		FileInputStream fis = new FileInputStream("D:\\下载\\asbd\\c.txt");
		int len = 0;
		while((len = fis.read()) != -1) {
			System.out.println((char)len);
		}
		fis.close();
		
		//int read()
		FileReader fr = new FileReader("D:\\下载\\asbd\\c.txt");
//		int len1 = 0;
//		while((len1 = fr.read()) != -1) {
//			System.out.println((char)len1);
//		}
//		fr.close();
		
		//int read(char[] cbuf) 
		char[] cs = new char[1024];
		int len2 = 0;
		while((len2 = fr.read(cs)) != -1) {
			System.out.println(new String(cs,0,len2));
		}
		fr.close();
	}
	public static void writer() throws IOException {
		/* java.io.writer：字符输出流，是所有字符输出流的最顶层父类，是一个抽象类
		 * 共性的成员方法：
		 * 		void write(int c) 写入单个字符
		 * 		void write(char[] cbuf) 写入字符数组
		 * 		abstract void write(char[] cbuf,int off,int len) 写入字符数组的一部分
		 * 		void write(String str) 写入字符串
		 * 		void write(String str,int off, int len) 写入字符串的一部分
		 * 		void flush() 刷新该流的缓冲
		 * 		void close() 关闭该流，但要先刷新它
		 * 
		 * java.io.FileWriter extends OutputStreamWriter extends Writer
		 * FileWriter：文件字符输出流
		 * 作用：把内存中的字符数据写入到文件中
		 * 
		 * 构造方法：
		 * 		FileWriter(File file) 根据给定的File对象构造一个FileWriter对象
		 * 		FileWriter(String filename) 根据给定的文件名构造一个FileWriter对象
		 * 		参数：写入数据的目的地
		 * 			String filename：文件的路径
		 * 			File file：是一个文件
		 * 		构造方法的作用：
		 * 			1、会创建一个FileWriter对象
		 * 			2、会根据构造方法中传递的文件/文件的路径，创建文件
		 * 			3、会把FileWriter对象指向创建好的文件
		 * 
		 * 字符输出流的使用步骤(重点)：
		 * 		1、创建FileWriter对象，构造方法中绑定要写入数据的目的地
		 * 		2、使用FileWriter中的方法writer，把数据写入到内存缓冲区中(字符转换为字节的过程)
		 * 		3、使用FileWriter中的方法flush，把内存缓冲区中的数据，刷新到文件中
		 * 		4、释放资源(会先把内存缓冲区中的数据刷新到文件中)
		 * 
		 * flush方法和close方法的区别：
		 * 		flush：刷新缓冲区，该对象可以继续使用
		 * 		close：先刷新缓冲区，然后通知系统释放资源，流对象不可以再被使用了
		 * 
		 * */
		
//		FileWriter fw = new FileWriter("D:\\下载\\asbd\\c.txt");
//		fw.write("97");
//		fw.flush();
//		fw.write(98);
//		fw.close();
		
		FileWriter fw = new FileWriter("D:\\下载\\asbd\\c.txt");
		char[] cs = {'a','b','c','d','e'};
		fw.write(cs);
		fw.write(cs,1,3);
		fw.write("冲撒旦法四大");
		fw.write("黑马程序员",2,3);
		fw.close();
	}
	public static void renew() throws IOException {
		/* 续写和换行
		 * 续写,使用两个参数的构造方法:
		 * 		FileWriter(String filename,boolean append)
		 * 		FileWriter(File file,boolean append)
		 * 		参数：
		 * 			boolean append:续写开关，true：不会创建新的文件覆盖原文件，false：创建新的文件覆盖原文件
		 * 换行：换行符号
		 * 		windows:\r\n
		 * 		Linux:/n
		 * 		mac:/r
		 * */
		FileWriter fw = new FileWriter("D:\\下载\\asbd\\c.txt",true);
		for(int i = 1;i <= 10;i++) {
			fw.write("helloworld" + i + "\r\n");
		}
		fw.close();
	}
	public static void tryCatch() throws IOException {
		/* 在JDK1.7之前使用try catch finally 处理流中的异常
		 * 变量在定义的时候，可以没有值，但是使用的时候必须有值
		 * */
		FileWriter fw = null;					//提高变量fw的作用域
		try {
			fw = new FileWriter("D:\\下载\\asbd\\c.txt",false);
			for(int i = 1;i <= 10;i++) {
				fw.write("helloworld" + i + "\r\n");
			}
			fw.close();
		}catch(IOException e) {
			e.printStackTrace();
		}finally {
			//创建对象失败了，fw的默认值就是null，null是不能调用方法的，会抛出空指针异常，所以需要增加一个判断，不是null在释放资源
			if(fw != null) {
				try {
					fw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		/* JDK7的新特性：
		 * 在try的后边可以增加一个(),在括号中可以定义流对象
		 * 那么这个对象的作用域就在try中有效
		 * try中的代码执行完毕，会自动把流对象释放，就不用写finally了
		 * 格式：
		 * 		try(定义流对象;定义流对象...){
		 * 			可能会出现异常的代码
		 * 		}catch(异常类变量 变量名){
		 * 			异常的处理逻辑
		 * 		}
		 * */
		try(FileInputStream fis = new FileInputStream("C:\\Users\\ASUS\\Downloads\\1.png");
			FileOutputStream fos = new FileOutputStream("D:\\下载\\asbd\\1.png")){
			int len = 0;
			while((len = fis.read()) != -1) {
				fos.write(len);
			}
		}catch(IOException e) {
			e.printStackTrace();
		}
		
		/* JDK9的新特性：
		 * try的前边可以定义流对象
		 * 在try的后边()中可以直接引入流对象的名称(变量名)
		 * 在try代码块执行完毕之后，流对象也可以释放掉，不用写finally
		 * 格式：
		 *  	A a = new A();
		 * 		B b = new B();
		 * 		try(a;b){
		 * 			可能会出现异常的代码
		 * 		}catch(异常类变量 变量名){
		 * 			异常的处理逻辑
		 * 		}
		 * */
		
		FileInputStream fis = new FileInputStream("C:\\Users\\ASUS\\Downloads\\1.png");
		FileOutputStream fos = new FileOutputStream("D:\\下载\\asbd\\1.png");
		try(fis;fos){
				int len = 0;
				while((len = fis.read()) != -1) {
					fos.write(len);
				}
			}catch(IOException e) {
				e.printStackTrace();
			}
	}
	public static void properties() {
		/* java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
		 * Properties 类表示了一个持久的属性集，Properties 可保存在流中或从流中加载，属性列表中的每个键及其对应值都是一个字符串
		 * Properties 集合是一个唯一和IO流相结合的集合
		 * 		可以使用Properties集合中的方法store,把集合中的临时数据，持久化写入到硬盘中存储
		 * 		可以使用Properties集合中的方法load，把硬盘中保存的文件(键对值)，读取到集合中使用
		 * 属性列表中的每个键及其对应值都是一个字符串：
		 * 		Properties 集合是一个双列集合，key和value默认都是字符串
		 * 
		 * 使用Properties集合储存数据，遍历取出Properties集合中的数据
		 * 因为Properties 集合是一个双列集合，key和value默认都是字符串
		 * 所以需要了解Properties集合中一些操作字符串的特有方法：
		 * 		Object setProperty(String key,String value) 调用 Hashtable 的方法 put
		 * 		Object getProperty(String key) 用指定的键在此属性列表中搜索属性(通过key找到value值，相当于get(key)方法)
		 * 		Set<String> stringPropertyNames() 返回此属性列表中的键集，其中该键及其对应的值是字符串 ，相当于Map集合中的keySet方法
		 * */
		
		Properties prop = new Properties();
		prop.setProperty("王诗宁", "175");
		prop.setProperty("刘青云", "180");
		prop.setProperty("张三丰", "999");
		
		Set<String> set = prop.stringPropertyNames();
		
		for(String key : set) {
			String value = prop.getProperty(key);
			System.out.println(key + "-->" +value);
		}
	}
	public static void propertiesStore() throws IOException {
		/* void store(OutputStream out,String comments)
		 * void store(Writer writer,String comments)
		 * 参数：
		 * 		OutputStream out：字节输出流，不能写入中文
		 * 		OutputStream out：字符输出流，可以写中文
		 * 		String comments：注释，用来解释说明保存的文件是做什么用的
		 * 			注释不能使用中文，会产生乱码，默认是Unicode编码，一般使用""空字符串
		 * 使用步骤：
		 * 		1、创建Properties集合对象，添加数据
		 * 		2、创建字节/字符输出流对象，构造方法中绑定要输出的目的地
		 * 		3、使用Properties集合中的方法store，把集合中的临时数据，持久化写入到硬盘中存储
		 * 		4、释放资源
		 * */
		Properties prop = new Properties();
		prop.setProperty("王诗宁", "175");
		prop.setProperty("刘青云", "180");
		prop.setProperty("张三丰", "999");
		
		FileWriter fw = new FileWriter("D:\\下载\\asbd\\c.txt");
		
		prop.store(fw,"save data");
		
		fw.close();
		
//		prop.store(new FileOutputStream("D:\\下载\\asbd\\c.txt"), "save data");
	}
	public static void propertiesLoad() throws IOException {
		/* void load(InputStream inStream)
		 * void load(Reader reader)
		 * 参数：
		 * 		InputStream inStream：字节输入流，不能读取含有中文的键值对
		 * 		Reader reader：字符输入流，能读取含有中文的键值对
		 * 使用步骤：
		 * 		1、创建Properties集合对象
		 * 		2、使用Properties集合对象中的方法load读取保存键值对的文件
		 * 		3、遍历Properties集合
		 * 注意：
		 * 		1、存储键值对的文件中，键与值默认的连接符号可以使用"="或者空格(或者其他符号)
		 * 		2、存储键值对的文件中，可以使用#进行注释，被注释的键值对不会再被读取
		 * 		3、存储键值对的文件中，键与值默认都是字符串，不用再加引号
		 * */
		Properties prop = new Properties();
		
		prop.load(new FileReader("D:\\下载\\asbd\\c.txt"));
		
		Set<String> set = prop.stringPropertyNames();
		for(String key : set) {
			String value = prop.getProperty(key);
			System.out.println(key + "-->" + value);
		}
	}
}
